/** Menu list mode handler.
@param buffer Buffer to render to.
@param width Width of the menu.
@param text Text to display above the menu area.
@param options An array of strings to select from. If this is null or an empty array, callback will be called with a null string after confirm or exit are pressed.
@param callback A callback method whos parameters are: option, the string that was selected (or null if no string was selected), source, the MenuListMode object that generated the callback. (Optional)
@param context The context of the callback. (Must be specified if callback is not null).
@param notCancelable If true this user will not be allowed to cancel out of the menu.
@param doNotClose If true this menu will not close before the callback is called. Use the close method to close the menu.
*/
function MenuListMode(buffer, width, text, options, callback, context, notCancelable, doNotClose)
{
	this.buffer = buffer;
	this.width = width;
	if(text == null ||
		text.length <= 0)
		this.lines = [];
	else
		this.lines = util.wordWrap(text, width);
	this.options = options;
	if(this.options == null)
		this.options = [];
	this.height = this.options.length + this.lines.length;
	if(this.lines.length > 0 &&
		this.options.length > 0)
		this.height += 1;
	this.callback = callback;
	this.callbackContext = context;
	this.notCancelable = notCancelable ? true : false;
	this.doNotClose = doNotClose ? true : false;
	this.selectedIndex = 0;
	this.render();
}
MenuListMode.prototype =
{
	/** Handle an input action.
	 *@param action The action string to handle.
	*/
	handleAction: function(action)
	{
		switch(action)
		{
			case "up":--this.selectedIndex;break;
			case "down":++this.selectedIndex;break;
			case "use":
				var option;
				if(this.selectedIndex < 0 ||
					this.selectedIndex > this.options.length)
					option = null;
				else
					option = this.options[this.selectedIndex];
				if(this.callback)
					this.callback.call(this.callbackContext, option, this);
				if(!this.doNotClose)
					this.close();
				return true;
				break;
			case "cancel":
				if(this.notCancelable)
					return true;
				if(this.callback)
					this.callback.call(this.callbackContext, null, this);
				if(!this.doNotClose)
					this.close();
				return true;
				break;
			default:return true;break;
		}
		if(this.selectedIndex < 0)
			this.selectedIndex = this.options.length - 1;
		if(this.selectedIndex >= this.options.length)
			this.selectedIndex = 0;
		this.render();
		return true;
	},
	/** Close this menu.
	 */
	close: function()
	{
		removeMode(this);
	},
	/** Render the menu.
	*/
	render: function()
	{
		var i;

		// Positioning and menu box
		var left = Math.floor((this.buffer.width - (this.width + 2)) / 2);
		var top = Math.floor((this.buffer.height - (this.height + 2)) / 2);
		this.buffer.drawMenuBox(left, top, this.width + 2, this.height + 2);
		this.buffer.drawBox(left, top, this.width + 2, this.height + 2, " ", null, Color.black);

		// Text
		var yOfs = top + 1;
		this.buffer.blitString(0, 0, "%f0");
		for(i = 0; i < this.lines.length; ++i)
		{
			this.buffer.blitString(left + 1, yOfs++, this.lines[i], this.width);
		}
		if(this.lines.length > 0 &&
			this.options.length > 0)
		{
			this.buffer.blitRect(left, yOfs++, this.width + 2, 1, " ", null, Color.black);
		}

		// Options
		var optionsTop = yOfs;
		for(i = 0; i < this.options.length; ++i)
		{
			var option = this.options[i];
			var leftOfs = Math.floor((this.width - option.length) / 2);
			if(leftOfs < 0)
				leftOfs = 0;
			this.buffer.blitRect(left + 1, yOfs, leftOfs, 1, " ", null, Color.black);
			this.buffer.blitString(left + 1 + leftOfs, yOfs++, "%f0" + option, this.width - leftOfs);
		}
		
		// Highlight selected option
		if(this.options.length > 0)
			this.buffer.blitRect(left, optionsTop + this.selectedIndex, this.width + 2, 1, null, null, Color.darkBlue);
	}
}
